package com.anandsoftware.db.io;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.anandsoftware.application.ApplicationContext;
import com.anandsoftware.db.ConnectionUtill;
import com.anandsoftware.db.type.DatabaseType;

//Testing remaining
public class DatabaseIO {

	private final Logger LOG = LoggerFactory.getLogger(DatabaseIO.class);
	private ConnectionUtill connectionFactory = ConnectionUtill
			.getConnectionUtil();
	private Connection connection = null;
	private int vendor = 0;

	/**
	 * 
	 * @param url
	 *            url of a database.
	 * @param databaseName
	 *            name of database.
	 * @param databaseClass
	 *            class name of a database Driver.
	 */
	public void init(String url, String databaseName, String databaseClass) {
		LOG.info("IO initialized with - ");
		LOG.info("[Url : " + url + ",DB Name : " + databaseName + ",Class : "
				+ databaseClass + "]");

		connectionFactory.setUrl(url);
		connectionFactory.setDatabaseName(databaseName);
		connectionFactory.setDatabaseClass(databaseClass);
		openConnection(vendor);
	}

	/**
	 * 
	 @param url
	 *            url of a database.
	 * @param databaseName
	 *            name of database.
	 * @param databaseClass
	 *            class name of a database Driver.
	 * @param username
	 *            username of a connection.
	 * @param password
	 *            password of a connection.
	 */
	public void init(String url, String databaseName, String databaseClass,
			String username, String password) {

		connectionFactory.setUsername(username);
		connectionFactory.setPassword(password);
		init(url, databaseName, databaseClass);
	}

	/**
	 * 
	 * @param url
	 *            url of database.
	 * @param databaseName
	 *            name of a database.
	 * @param username
	 *            username of a connection.
	 * @param password
	 *            password of a connection.
	 * @param vendor
	 *            name of a database vendor {@link DatabaseType}
	 */
	public void init(String databaseName, String username, String password,
			int vendor) {
		connectionFactory.setPassword(password);
		connectionFactory.setUsername(username);
		this.vendor = vendor;
		init("", databaseName, "");
	}

	/**
	 * 
	 * @param url
	 *            url of database.
	 * @param databaseName
	 *            name of a database.
	 * @param vendor
	 *            name of a database vendor {@link DatabaseType}
	 */
	public void init(String databaseName, int vendor) {
		this.vendor = vendor;
		init("", databaseName, "");
	}

	/**
	 * 
	 * @param vendor
	 *            name of the database vendor {@link DatabaseType}. opens a
	 *            conncetion
	 */
	private void openConnection(int vendor) {
		if (vendor == 0) {
			connection = connectionFactory.getConnection();
		} else {
			connection = connectionFactory.getConnection(vendor);
		}
	}

	/**
	 * saves <k,v> to database.
	 * 
	 * @param property
	 *            used as key
	 * @param value
	 *            value of a key
	 */
	public void save(String property, String value) {
		try {
			LOG.info("Property Saved : " + property);
			Statement st = connection.createStatement();
			st.execute("insert into " + ApplicationContext.DEFAULT_TABLE_NAME
					+ " values ('" + property + "','" + value + "');");
			st.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	/**
	 * updates <k,v> in database using key.
	 * 
	 * @param property
	 *            used as key
	 * @param value
	 *            value of a key
	 */
	public void update(String property, String value) {
		try {
			LOG.info("Property Updated : " + property);
			Statement st = connection.createStatement();
			st.execute("update " + ApplicationContext.DEFAULT_TABLE_NAME
					+ " set value = '" + value + "' where `key` = '" + property
					+ "';");
			st.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	/**
	 * removes <k,v> from database using key.
	 * 
	 * @param property
	 *            used as key
	 * @param value
	 *            value of a key
	 */
	public void remove(String property) {
		try {
			LOG.info("Property Removed : " + property);
			Statement st = connection.createStatement();
			st.execute("delete * from " + ApplicationContext.DEFAULT_TABLE_NAME
					+ " where `key` = '" + property + "';");
			st.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param property
	 *            key of <k.v>
	 * @return value of the entered key.
	 */
	public String getValue(String property) {
		try {
			LOG.info("Property Selected : " + property);
			Statement st = connection.createStatement();
			ResultSet rs = st.executeQuery("select * from "
					+ ApplicationContext.DEFAULT_TABLE_NAME
					+ " where `key` = '" + property + "';");
			rs.next();
			return rs.getString("value");
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 
	 * @return returns all <k,v> in form of map.
	 */
	public Map<String, String> getAll() {
		Map<String, String> properties = new HashMap<String, String>();
		try {
			Statement st = connection.createStatement();
			ResultSet rs = st.executeQuery("select * from "
					+ ApplicationContext.DEFAULT_TABLE_NAME);
			while (rs.next()) {
				properties.put(rs.getString("key"), rs.getString("value"));
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return properties;
	}

	/**
	 * 
	 * @param properties
	 *            saves <k.v> map to database.
	 */
	public void save(Map<String, String> properties) {
		try {
			PreparedStatement st = connection.prepareStatement("insert into "
					+ ApplicationContext.DEFAULT_TABLE_NAME + " values (?,?);");

			for (Entry<String, String> entry : properties.entrySet()) {
				st.setString(1, entry.getKey());
				st.setString(2, entry.getValue());
				st.addBatch();
			}
			connection.setAutoCommit(false);
			st.executeBatch();
			connection.setAutoCommit(true);
			st.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	/**
	 * creates new table to database.
	 */
	public void createTable() {
		try {
			LOG.info("In Table Created : " + ApplicationContext.DEFAULT_TABLE_NAME);
			Statement st = connection.createStatement();
			st.execute("CREATE TABLE IF NOT EXISTS "
					+ ApplicationContext.DEFAULT_TABLE_NAME
					+ " (`key` VARCHAR(100),`value` VARCHAR(300));");
			st.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	public void closeDatabase() {
		if (connection != null) {
			try {
				connection.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
